/*
 * Copyright (c) 2010 Andy Aspell-Clark
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
package uk.org.aspellclark.gedcom;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import uk.org.aspellclark.gedcom.controller.Db4oController;
import uk.org.aspellclark.gedcom.controller.FamilyController;
import uk.org.aspellclark.gedcom.controller.HeaderController;
import uk.org.aspellclark.gedcom.controller.IndividualController;
import uk.org.aspellclark.gedcom.controller.MultimediaController;
import uk.org.aspellclark.gedcom.controller.NoteController;
import uk.org.aspellclark.gedcom.controller.RepositoryController;
import uk.org.aspellclark.gedcom.controller.SourceController;
import uk.org.aspellclark.gedcom.controller.SubmissionController;
import uk.org.aspellclark.gedcom.controller.SubmitterController;
import uk.org.aspellclark.gedcom.model.ChangeDate;
import uk.org.aspellclark.gedcom.model.ChildToFamilyLink;
import uk.org.aspellclark.gedcom.model.EventDetail;
import uk.org.aspellclark.gedcom.model.FamilyEventType;
import uk.org.aspellclark.gedcom.model.IndividualEventType;
import uk.org.aspellclark.gedcom.model.PersonalNamePieces;
import uk.org.aspellclark.gedcom.model.SpouseToFamilyLink;
import uk.org.aspellclark.gedcom.model.UserReference;
import uk.org.aspellclark.gedcom.model.records.FamRecord;
import uk.org.aspellclark.gedcom.model.records.Header;
import uk.org.aspellclark.gedcom.model.records.IndividualRecord;
import uk.org.aspellclark.gedcom.model.records.MultimediaRecord;
import uk.org.aspellclark.gedcom.model.records.NoteRecord;
import uk.org.aspellclark.gedcom.model.records.RepositoryRecord;
import uk.org.aspellclark.gedcom.model.records.SourceRecord;
import uk.org.aspellclark.gedcom.model.records.SubmissionRecord;
import uk.org.aspellclark.gedcom.model.records.SubmitterRecord;
import uk.org.aspellclark.gedcom.model.structures.AddressStructure;
import uk.org.aspellclark.gedcom.model.structures.FamilyEventStructure;
import uk.org.aspellclark.gedcom.model.structures.IndividualEventStructure;
import uk.org.aspellclark.gedcom.model.structures.NoteStructure;
import uk.org.aspellclark.gedcom.model.structures.PersonalNameStructure;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

/**
 *
 * @author andy.aspell-clark
 */
public final class GedcomParser {

	private HeaderController headerCntrlr;
	private FamilyController familyCntrlr;
	private IndividualController individualCntrlr;
	private MultimediaController multimediaCntrlr;
	private NoteController noteCntrlr;
	private RepositoryController repositoryCntrlr;
	private SourceController sourceCntrlr;
	private SubmitterController submitterCntrlr;
	private SubmissionController submissionCntrlr;

	/**
	 * The things that went wrong while parsing the gedcom file.
	 */
	public List<String> errors = new ArrayList<String>();

	/**
	 * The warnings issued during the parsing of the gedcom file.
	 */
	public List<String> warnings = new ArrayList<String>();

	private FileReader gedcomFileRdr;
	private BufferedReader bufferedReader = null;
	private String currLineRead = "";

	private int currLineNbr = 0;
	private int currBytesRead = 0;
	private int currParsingProgress;

	private boolean mergeNewDataIntoCurrent = false;

	//private String filename;
	private Handler progressHandler;
	private Message hndlrMsg;

	private Db4oController dbCntrlr = null;

	public GedcomParser() {
	}

	private void fileClose() {
		try {
			this.bufferedReader.close();
			this.gedcomFileRdr.close();
			this.bufferedReader = null;
			this.gedcomFileRdr = null;
		} catch (Exception e) {
			//Log.e(LOG_TAG, e.getMessage());
		}
	}

	private void fileOpen(String filename) throws FileNotFoundException {
		File gedcomFile = new File(filename);
		this.gedcomFileRdr = new FileReader(gedcomFile);
		this.bufferedReader = new BufferedReader(this.gedcomFileRdr, 16384);
	}

	private void fileReadFirstLine() {
		try {
			this.currLineRead = null;
			this.currLineRead = this.bufferedReader.readLine().trim();
			this.currBytesRead = this.currLineRead.length();
			this.currLineNbr = 0;
			this.currLineRead.trim();
		} catch (IOException e) {
			this.currLineRead = "";
		}
	}

	private void fileReadNextLine() {
		try {
			this.currLineRead = null;
			this.currLineRead = this.bufferedReader.readLine();
			if (this.currLineRead != null) {
				this.currBytesRead += this.currLineRead.length();
			}
			this.currLineRead.trim();
			this.currLineNbr++;
		} catch (Throwable e) {
			//Log.e(LOG_TAG, e.getMessage());
			this.errors.add("Error parsing Gedcom file [" + e.getMessage() + "]");
			this.currLineRead = "";
		}
	}

	private String getIdFromString(CharSequence cs) {
		StringBuffer retStr = new StringBuffer();

		for (int x = 0; x < cs.length(); x++) {
			char ch = cs.charAt(x);
			if (ch == '@') {
				retStr.append(ch);
				x++;
				ch = cs.charAt(x);
				while (ch != '@') {
					retStr.append(ch);
					x++;
					ch = cs.charAt(x);
				}
				retStr.append(ch);
				break;
			}
		}
		return retStr.toString();
	}

	/** extract the level number from a gedcom line
	 */
	private int getLevelNum(String txtLine) {
		return Integer.parseInt(txtLine.substring(0, 1));
	}

	private AddressStructure importAddressStructure(int currentLevelNumber) {

		AddressStructure addr = new AddressStructure();
		StringBuffer addressDetails = new StringBuffer();
		if (this.currLineRead.length() > 7) {
			addressDetails.append(this.currLineRead.substring(7, this.currLineRead.length())); //get data after '0 ADDR' which are tokens 0 and 1
		}

		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}
			//Here we handle the different fields from the Address Structure
			if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_CONT) > 0) {
				//We now have a CONTinuation line, so we append it to the end of the address
				addressDetails.append(", ");
				if (this.currLineRead.length() > 7) {
					addressDetails.append(this.currLineRead.substring(7, this.currLineRead.length())); //get data after '2 CONT' which are tokens 0 and 1
				}
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_ADR1) > 0) {
				addressDetails.append(", ");
				if (this.currLineRead.length() > 7) {
					addressDetails.append(this.currLineRead.substring(7, this.currLineRead.length())); //get data after '2 CONT' which are tokens 0 and 1
				}
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_ADR2) > 0) {
				addr.addr2 = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_CITY) > 0) {
				addr.city = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_STAE) > 0) {
				addr.stateProvince = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_POST) > 0) {
				addr.postalCode = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_CTRY) > 0) {
				addr.country = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else {
				this.fileReadNextLine();
			}
		}
		addr.addr1 = addressDetails.toString();

		return addr;

	}

	private ChangeDate importChangeDate(int currentLevelNumber) {
		ChangeDate tmpObj = new ChangeDate();
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}
			if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_DATE) > 0) {
				tmpObj.date = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_TIME) > 0) {
				tmpObj.time = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_NOTE) > 0) {
				if (tmpObj.note == null) {
					tmpObj.note = new ArrayList<NoteStructure>();
				}
				tmpObj.note.add(this.importNoteStructure(this.getLevelNum(this.currLineRead)));
				this.fileReadNextLine();
			} else {
				this.fileReadNextLine();
			}
		}
		return tmpObj;
	}

	private FamilyEventStructure importFamilyEvent(int currentLevelNumber) {

		FamilyEventStructure tmpObj = new FamilyEventStructure();
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}
			if (this.currLineRead.indexOf("HUSB") > 0) {
				this.fileReadNextLine();
				tmpObj.detail.husbAge = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("WIFE") > 0) {
				this.fileReadNextLine();
				tmpObj.detail.wifeAge = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_DATE) > 0) {
				tmpObj.detail.eventDetail.date = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("TYPE") > 0) {
				tmpObj.detail.eventDetail.type = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("CAUS") > 0) {
				tmpObj.detail.eventDetail.cause = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("RELI") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_RESN) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("PLAC") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("AGNC") > 0) {
				tmpObj.detail.eventDetail.resn = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_NOTE) > 0) {
				//FIXME: tmpObj.eventDetail.notes.add(this.importNoteRecord(this.getLevelNum(this.currLineRead)));
				this.fileReadNextLine();
			} else {
				this.fileReadNextLine();
			}
		}
		return tmpObj;
	}

	private void importFamilyRecord(int currentLevelNumber) {
		//create a new family in the data model
		FamRecord famly = new FamRecord(this.getIdFromString(this.currLineRead));
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_RESN) > 0) {
				famly.restrictionNotice = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (FamilyEventType.isValidTag(this.currLineRead.substring(2, this.currLineRead.length()).trim())) {
				FamilyEventStructure tmpEvent = this.importFamilyEvent(this.getLevelNum(this.currLineRead));
				if (famly.events == null) {
					famly.events = new ArrayList<FamilyEventStructure>();
				}
				famly.events.add(tmpEvent);
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_HUSB) > 0) {
				famly.husb = this.getIdFromString(this.currLineRead);
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_WIFE) > 0) {
				famly.wife = this.getIdFromString(this.currLineRead);
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_CHIL) > 0) {
				famly.childrenXRef.add(this.getIdFromString(this.currLineRead));
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_NCHI) > 0) {
				//FIXME: famly.numChildren = Integer.parseInt(this.currLineRead.substring(7, this.currLineRead.length()));
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_SUBM) > 0) {
				//FIXME: famly.submitters.add(this.currLineRead.substring(7, this.currLineRead.length()));
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_REFN) > 0) {
				UserReference ur = new UserReference();
				ur.number = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
				if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_TYPE) > 0) {
					ur.type = this.currLineRead.substring(7, this.currLineRead.length());
				}
				famly.refn.add(ur);
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_RIN) > 0) {
				famly.rin = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_CHAN) > 0) {
				famly.changeDate = this.importChangeDate(this.getLevelNum(this.currLineRead));
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_NOTE) > 0) {
				NoteStructure nte = this.importNoteStructure(this.getLevelNum(this.currLineRead));
				if (famly.note == null) {
					famly.note = new ArrayList<NoteStructure>();
				}
				famly.note.add(nte);
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_SOUR) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_OBJE) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else {
				this.fileReadNextLine();
			}
		}
		this.familyCntrlr.addFamily(famly);
	}

	private void importHeaderRecord(int currentLevelNumber) {
		this.fileReadNextLine();
		Header hdr = new Header();

		boolean inGedC = false;
		//boolean inChar = false;

		//Loop while there are no errors reading in from the file
		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}

			if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_SOUR) > 0) {
				hdr.sour = this.importHeaderSourceSystem(hdr, this.getLevelNum(this.currLineRead));
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_NAME) > 0) {
				hdr.sour.name += " " + this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_DEST) > 0) {
				hdr.dest = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_DATE) > 0) {
				StringBuffer sb = new StringBuffer(this.currLineRead.substring(7, this.currLineRead.length()));
				this.fileReadNextLine();
				hdr.date = sb.toString();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_TIME) > 0) {
				StringBuffer sb = new StringBuffer(this.currLineRead.substring(7, this.currLineRead.length()));
				this.fileReadNextLine();
				hdr.time = sb.toString();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_SUBN) > 0) {
				hdr.subnXRef.add(this.currLineRead.substring(7, this.currLineRead.length()));
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_SUBM) > 0) {
				hdr.submXRef.add(this.currLineRead.substring(7, this.currLineRead.length()));
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_GEDC) > 0) {
				inGedC = true;
				this.fileReadNextLine();
				if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_VERS) > 0) {
					String tmpVersion = this.currLineRead.substring(7, this.currLineRead.length());
					this.fileReadNextLine();
					String tmpForm = "";
					if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_FORM) > 0) {
						tmpForm = this.currLineRead.substring(7, this.currLineRead.length());
						this.fileReadNextLine();
					}
					if (inGedC) {
						hdr.gedcVersion = tmpVersion;
						hdr.gedcForm = tmpForm;
					} else {
						hdr.charsetVers = tmpVersion;
					}
				}
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_CHAR) > 0) {
				//inChar = true;
				hdr.charset = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_COPR) > 0) {
				hdr.copyright += "\n" + this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_LANG) > 0) {
				hdr.language = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_PLAC) > 0) {
				StringBuffer sb = new StringBuffer(this.getIdFromString(this.currLineRead));
				this.fileReadNextLine();
				if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_FORM) > 0) {
					sb.append(" : ").append(this.currLineRead.substring(7, this.currLineRead.length()));
					this.fileReadNextLine();
				}
				hdr.placeHierarchy = sb.toString();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_FILE) > 0) {
				hdr.fileName = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_NOTE) > 0) {
				hdr.note = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
				while (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_CONC) > 0
						|| this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_CONT) > 0) {
					hdr.note += this.currLineRead.substring(7, this.currLineRead.length());
					this.fileReadNextLine();
				}
			} else {
				this.fileReadNextLine();
			}
		}
		this.headerCntrlr.addHeader(hdr);
	}

	private Header.Source importHeaderSourceSystem(Header hdr, int currentLevelNumber) {
		Header.Source hdrSrcSystem = hdr.sour;

		hdrSrcSystem.id = this.currLineRead.substring(7, this.currLineRead.length());

		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}
			if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_VERS) > 0) {
				hdrSrcSystem.version = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_NAME) > 0) {
				hdrSrcSystem.data = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_CORP) > 0) {
				hdrSrcSystem.corpName = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
				hdrSrcSystem.corpAddress = this.importAddressStructure(this.getLevelNum(this.currLineRead));
			}
			if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_DATE) > 0) {
				hdrSrcSystem.dataDate = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_COPR) > 0) {
				StringBuffer sb = new StringBuffer(this.currLineRead.substring(7, this.currLineRead.length()));
				this.fileReadNextLine();
				while (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_CONC) > 0
						|| this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_CONT) > 0) {
					sb.append(' ').append(this.currLineRead.substring(7, this.currLineRead.length()));
				}
				hdrSrcSystem.dataCopyright = sb.toString();
			}
			this.fileReadNextLine();
		}
		return hdrSrcSystem;
	}

	private IndividualEventStructure importIndividualEvent(int currentLevelNumber) {
		IndividualEventStructure tmpObj = new IndividualEventStructure();

		if (this.currLineRead.length() > 5) {
			tmpObj.type = IndividualEventType.getFromTag(this.currLineRead.substring(1, 6).trim());
		}
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}

			if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_AGE) > 0) {
				tmpObj.detail.ageAtEvent = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_DATE) > 0) {
				if (tmpObj.detail.eventDetail == null) {
					tmpObj.detail.eventDetail = new EventDetail();
				}
				tmpObj.detail.eventDetail.date = this.currLineRead.substring(7, this.currLineRead.length());
				tmpObj.detail.date = tmpObj.detail.eventDetail.date;
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_CAUS) > 0) {
				tmpObj.setCause(this.currLineRead.substring(7, this.currLineRead.length()));
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_RELI) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_RESN) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_AGNC) > 0) {
				tmpObj.detail.eventDetail.agnc = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_NOTE) > 0) {
				NoteStructure nte = this.importNoteStructure(this.getLevelNum(this.currLineRead));
				if (tmpObj.detail.eventDetail.note == null) {
					tmpObj.detail.eventDetail.note = new ArrayList<NoteStructure>();
				}
				tmpObj.detail.eventDetail.note.add(nte);
				this.fileReadNextLine();
			} else {
				this.fileReadNextLine();
			}
		}
		return tmpObj;
	}

	private ChildToFamilyLink importIndividualFamilyChild(int currentLevelNumber) {
		ChildToFamilyLink tmpObj = new ChildToFamilyLink();

		tmpObj.famcXRef = this.getIdFromString(this.currLineRead);
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}
			if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_NOTE) > 0) {
				NoteStructure nte = this.importNoteStructure(this.getLevelNum(this.currLineRead));
				if (tmpObj.note == null) {
					tmpObj.note = new ArrayList<NoteStructure>();
				}
				tmpObj.note.add(nte);
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("PEDI") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("ADOP") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else {
				this.fileReadNextLine();
			}
		}
		return tmpObj;
	}

	private SpouseToFamilyLink importIndividualFamilySpouse(int currentLevelNumber) {
		SpouseToFamilyLink tmpObj = new SpouseToFamilyLink();

		tmpObj.famsXRef = this.getIdFromString(this.currLineRead);
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}
			if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_NOTE) > 0) {
				NoteStructure nte = this.importNoteStructure(this.getLevelNum(this.currLineRead));
				if (tmpObj.note == null) {
					tmpObj.note = new ArrayList<NoteStructure>();
				}
				tmpObj.note.add(nte);
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("PEDI") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("ADOP") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else {
				this.fileReadNextLine();
			}
		}
		return tmpObj;
	}

	/**
	 * Import a personal name structure for an individual.
	 *
	 * @param acurrLineRead the first line of the record
	 * @param currentLevelNumber the record level number for this record
	 * @return a PersonalName structure
	 */
	private PersonalNameStructure importIndividualPersonalName(int currentLevelNumber) {
		PersonalNameStructure pn = new PersonalNameStructure();
		pn.name = this.currLineRead.substring(7, this.currLineRead.length());

		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}
			try {
				if (this.currLineRead.indexOf("NPFX") > 0) {
					if (pn.pieces == null) {
						pn.pieces = new PersonalNamePieces();
					}
					pn.pieces.prefix = this.currLineRead.substring(7, this.currLineRead.length());

				} else if (this.currLineRead.indexOf("GIVN") > 0) {
					if (this.currLineRead.length() > 7) {
						if (pn.pieces == null) {
							pn.pieces = new PersonalNamePieces();
						}
						pn.pieces.given = this.currLineRead.substring(7, this.currLineRead.length());
					}
				} else if (this.currLineRead.indexOf("NICK") > 0) {
					if (this.currLineRead.length() > 7) {
						if (pn.pieces == null) {
							pn.pieces = new PersonalNamePieces();
						}
						pn.pieces.nickname = this.currLineRead.substring(7, this.currLineRead.length());
					}
				} else if (this.currLineRead.indexOf("SPFX") > 0) {
					if (this.currLineRead.length() > 7) {
						if (pn.pieces == null) {
							pn.pieces = new PersonalNamePieces();
						}
						pn.pieces.surnamePrefix = this.currLineRead.substring(7, this.currLineRead.length());
					}
				} else if (this.currLineRead.indexOf("SURN") > 0) {
					if (pn.pieces == null) {
						pn.pieces = new PersonalNamePieces();
					}
					pn.pieces.surname = this.currLineRead.substring(7, this.currLineRead.length());

				} else if (this.currLineRead.indexOf("NSFX") > 0) {
					if (this.currLineRead.length() > 7) {
						if (pn.pieces == null) {
							pn.pieces = new PersonalNamePieces();
						}
						pn.pieces.suffix = this.currLineRead.substring(7, this.currLineRead.length());
					}
				} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_SOUR) > 0) {
					//FIXME : Finish import
				} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_NOTE) > 0) {
					NoteStructure nte = this.importNoteStructure(this.getLevelNum(this.currLineRead));
					if (pn.pieces.note == null) {
						pn.pieces.note = new ArrayList<NoteStructure>();
					}
					pn.pieces.note.add(nte);
					//this.fileReadNextLine();
				}
			} catch (Exception e) {
				String msg = e.getMessage();
				Log.e("GedcomParser", msg);
			}
			this.fileReadNextLine();

		}
		return pn;
	}

	/**
	 * read in an individual record and add it to the gedcom store.
	 * @param acurrLineRead the first line of the record
	 * @param currentLevelNumber the record level number for this record
	 * @return the individual record read in from the file
	 */
	private void importIndividualRecord(int currentLevelNumber) {
		IndividualRecord ind = new IndividualRecord(this.currLineRead.substring(2, this.currLineRead.length() - 5));

		this.fileReadNextLine();
		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_NAME) > 0) {
				PersonalNameStructure pn = this.importIndividualPersonalName(this.getLevelNum(this.currLineRead));
				if (ind.names == null) {
					ind.names = new ArrayList<PersonalNameStructure>();
				}
				ind.names.add(pn);
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_RESN) > 0) {
				ind.resn = this.currLineRead.substring(7, this.currLineRead.length() - 1);
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("SEX") > 0) {
				ind.sex = this.currLineRead.substring(this.currLineRead.length() - 1, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (IndividualEventType.isValidTag(this.currLineRead.substring(2, this.currLineRead.length()).trim())) {
				if (ind.indEvent == null) {
					ind.indEvent = new ArrayList<IndividualEventStructure>();
				}
				ind.indEvent.add(this.importIndividualEvent(this.getLevelNum(this.currLineRead)));
			} else if (this.currLineRead.indexOf("FAMC") > 0) {
				ChildToFamilyLink fc = this.importIndividualFamilyChild(this.getLevelNum(this.currLineRead));
				if (ind.childLink == null) {
					ind.childLink = new ArrayList<ChildToFamilyLink>();
				}
				ind.childLink.add(fc);
			} else if (this.currLineRead.indexOf("FAMS") > 0) {
				SpouseToFamilyLink fs = this.importIndividualFamilySpouse(this.getLevelNum(this.currLineRead));
				if (ind.spouseLink == null) {
					ind.spouseLink = new ArrayList<SpouseToFamilyLink>();
				}
				ind.spouseLink.add(fs);
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_SUBM) > 0) {
				if (ind.submXRef == null) {
					ind.submXRef = new ArrayList<String>();
				}
				ind.submXRef.add(this.currLineRead.substring(7, this.currLineRead.length() - 1));
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("ASSO") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("ALIA") > 0) {
				if (ind.aliasXRef == null) {
					ind.aliasXRef = new ArrayList<String>();
				}
				ind.aliasXRef.add(this.currLineRead.substring(7, this.currLineRead.length() - 1));
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("ANCI") > 0) {
				if (ind.anciXRef == null) {
					ind.anciXRef = new ArrayList<String>();
				}
				ind.anciXRef.add(this.currLineRead.substring(7, this.currLineRead.length() - 1));
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("DESI") > 0) {
				if (ind.desiXRef == null) {
					ind.desiXRef = new ArrayList<String>();
				}
				ind.desiXRef.add(this.currLineRead.substring(7, this.currLineRead.length() - 1));
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_SOUR) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("OBJE") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_NOTE) > 0) {
				if (ind.note == null) {
					ind.note = new ArrayList<NoteStructure>();
				}
				ind.note.add(this.importNoteStructure(this.getLevelNum(this.currLineRead)));
			} else if (this.currLineRead.indexOf("RFN") > 0) {
				ind.rfn = this.currLineRead.substring(7, this.currLineRead.length() - 1);
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("AFN") > 0) {
				ind.afn = this.currLineRead.substring(7, this.currLineRead.length() - 1);
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_REFN) > 0) {
				UserReference ur = new UserReference();
				ur.number = this.currLineRead.substring(7, this.currLineRead.length() - 1);
				this.fileReadNextLine();
				if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_TYPE) > 0) {
					ur.type = this.currLineRead.substring(7, this.currLineRead.length() - 1);
					this.fileReadNextLine();
				}
				if (ind.refn == null) {
					ind.refn = new ArrayList<UserReference>();
				}
				ind.refn.add(ur);
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_RIN) > 0) {
				ind.rin = this.currLineRead.substring(7, this.currLineRead.length() - 1);
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_CHAN) > 0) {
				ind.changeDate = this.importChangeDate(this.getLevelNum(this.currLineRead));
			} else {
				this.fileReadNextLine();
			}
		}
		this.individualCntrlr.addIndividual(ind);
	}

	/**
	 * Import a multimedia record.
	 *
	 * @param acurrLineRead the first line of the record
	 * @param currentLevelNumber the record level number for this record
	 * @return a multimedia record
	 */
	private void importMultimediaRecord(int currentLevelNumber) {
		MultimediaRecord tmpObj = new MultimediaRecord(this.getIdFromString(this.currLineRead));
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}

			//FIXME : Finish import
			this.fileReadNextLine();
		}
		this.multimediaCntrlr.addMultimedia(tmpObj);
	}

	/**
	 * Import a note record.
	 * @see uk.org.aspellclark.gedcom.model.records.NoteRecord
	 *
	 * @param currentLevelNumber the record level number for this record
	 * @return a Note Record
	 */
	private NoteRecord importNoteRecord(int currentLevelNumber) {
		NoteRecord tmpObj = new NoteRecord(this.getIdFromString(this.currLineRead));
		if (this.currLineRead.length() > 6) {
			//FIXME : tmpObj.lines.add(this.currLineRead.substring(7, this.currLineRead.length()));
		}

		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}

			if ((this.currLineRead.indexOf("CONC") > 0) || (this.currLineRead.indexOf("CONT") > 0)) {
				if (this.currLineRead.length() > 6) {
					//FIXME : tmpObj.lines.add(new StringBuffer(" ").append(this.currLineRead.substring(7, this.currLineRead.length())).toString());
				}
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("REFN") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("RIN") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_SOUR) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_CHAN) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else {
				this.fileReadNextLine();
			}
		}
		this.noteCntrlr.addNote(tmpObj);
		return tmpObj;
	}

	/**
	 * @param levelNum
	 * @return
	 */
	private NoteStructure importNoteStructure(int currentLevelNumber) {
		NoteStructure tmpObj = new NoteStructure();
		if (this.currLineRead.length() > 6) {
			//FIXME : tmpObj.lines.add(this.currLineRead.substring(7, this.currLineRead.length()));
		}

		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}

			if (this.currLineRead.indexOf("NOTE @") != -1) {
				tmpObj.noteXRef = this.getIdFromString(this.currLineRead);
			} else {
				tmpObj.note = this.currLineRead.substring(5);

				this.fileReadNextLine();
				while ((this.currLineRead.indexOf("CONC") > 0) || (this.currLineRead.indexOf("CONT") > 0)) {
					if (this.currLineRead.length() > 6) {
						//FIXME : tmpObj.lines.add(new StringBuffer(" ").append(this.currLineRead.substring(7, this.currLineRead.length())).toString());

						this.fileReadNextLine();
					}
					this.fileReadNextLine();
				}
			}
		}
		return tmpObj;
	}

	private void importRepositoryRecord(int currentLevelNumber) {
		RepositoryRecord rpos = new RepositoryRecord(this.getIdFromString(this.currLineRead));
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}
			//Here we handle the different fields from the Header record
			if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_SUBM) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("FAMF") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else {
				this.fileReadNextLine();
			}
		}
		this.repositoryCntrlr.addRepository(rpos);
	}

	private void importSourcePrimitive(int currentLevelNumber) {
		SourceRecord sour = new SourceRecord(this.getIdFromString(this.currLineRead));
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_SUBM) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("FAMF") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else {
				this.fileReadNextLine();
			}
		}
		this.sourceCntrlr.addSource(sour);
	}

	private void importSubmissionRecord(int currentLevelNumber) {
		SubmissionRecord subm = null;
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_SUBM) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("FAMF") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else {
				this.fileReadNextLine();
			}
		}
		this.submissionCntrlr.addSubmission(subm);
	}

	private void importSubmitterRecord(int currentLevelNumber) {
		SubmitterRecord subm = new SubmitterRecord(this.getIdFromString(this.currLineRead));
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_NAME) > 0) {
				subm.name = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_ADDR) > 0) {
				subm.address = this.importAddressStructure(this.getLevelNum(this.currLineRead));
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_PHON) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_LANG) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_RFN) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_RIN) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GedcomConstants.GEDCOM_TAG_CHAN) > 0) {
				this.importChangeDate(this.getLevelNum(this.currLineRead));
			} else {
				this.fileReadNextLine();
			}
		}
		this.submitterCntrlr.addSubmitter(subm);
	}

	public void initialise(String dbFilename, boolean mergeData) {
		this.mergeNewDataIntoCurrent = mergeData;
		this.dbCntrlr = Db4oController.getInstance();
		this.dbCntrlr.dbFilename = dbFilename;
		this.headerCntrlr = new HeaderController(this.dbCntrlr);
		this.familyCntrlr = new FamilyController(this.dbCntrlr);
		this.individualCntrlr = new IndividualController(this.dbCntrlr);
		this.multimediaCntrlr = new MultimediaController(this.dbCntrlr);
		this.noteCntrlr = new NoteController(this.dbCntrlr);
		this.repositoryCntrlr = new RepositoryController(this.dbCntrlr);
		this.sourceCntrlr = new SourceController(this.dbCntrlr);
		this.submitterCntrlr = new SubmitterController(this.dbCntrlr);
		this.submissionCntrlr = new SubmissionController(this.dbCntrlr);
		//this.changeDateCntrlr = new ChangeDateController(this.dbCntrlr);
	}

	/**
	 * opens the gedcom file, reads it's contents in and parses them into
	 * the gedcom data model.
	 * @param progressHandler 
	 */
	public void parse(String filename, Handler progressHndlr) {
		// start tracing to "/sdcard/GedcomParse.trace"
		//Debug.startMethodTracing("GedcomParse");

		this.errors = new ArrayList<String>();
		this.warnings = new ArrayList<String>();

		this.currBytesRead = 0;
		this.progressHandler = progressHndlr;
		if (this.progressHandler != null) {
			this.hndlrMsg = this.progressHandler.obtainMessage(this.currBytesRead);
		}

		try {
			if (!this.mergeNewDataIntoCurrent) {
				this.dbCntrlr.clearDatabase();
				//				this.dbCntrlr.deleteDatabase();
				this.dbCntrlr.openDatabase();
			}
			this.fileOpen(filename);
			this.fileReadFirstLine();

			//if first line of file isn't "0 HEAD" then the file is not in GedCom format
			if (this.currLineRead.length() == 0 || !(this.currLineRead.indexOf("0 HEAD") == 0)) {
				//File is too short to be a Gedcom File
				this.fileClose();
				return;
			}
			int currentLevelNumber = 0;
			while (this.currLineRead != null && this.currLineRead.length() > 0) {
				this.updateProgressHandler();
				try {
					//each of the following routines handles a single record type
					//We expect the routine to read in the first line of the Next
					//record (that is each record handler will read in the first line
					//of the record that follows it).
					if (this.currLineRead.indexOf("0") == 0) {
						if (this.currLineRead.indexOf("INDI") == (this.currLineRead.length() - 4)) {
							this.importIndividualRecord(currentLevelNumber);
						} else if (this.currLineRead.indexOf("FAM") == (this.currLineRead.length() - 3)) {
							this.importFamilyRecord(currentLevelNumber);
						} else if (this.currLineRead.indexOf("0 NOTE") == 0) {
							this.importNoteRecord(currentLevelNumber);
						} else if (this.currLineRead.indexOf("0 REPO") == 0) {
							this.importRepositoryRecord(currentLevelNumber);
						} else if (this.currLineRead.indexOf("0 SOUR") == 0) {
							this.importSourcePrimitive(currentLevelNumber);
						} else if (this.currLineRead.indexOf("0 SUBM") == 0) {
							this.importSubmitterRecord(currentLevelNumber);
						} else if (this.currLineRead.indexOf("0 SUBN") == 0) {
							this.importSubmissionRecord(currentLevelNumber);
						} else if (this.currLineRead.indexOf("0 OBJE") == 0) {
							this.importMultimediaRecord(currentLevelNumber);
						} else if (this.currLineRead.indexOf("0 TRLR") == 0) {
							//the "0 TRLR" record just tells us that we have reached the end
							//of the file, so we 'break' out of the while loop
							break;
						} else if (this.currLineRead.indexOf("0 HEAD") == 0) {
							this.importHeaderRecord(currentLevelNumber);
						} else {
							this.fileReadNextLine();
						}
					} else {
						this.warnings.add("unknown tag found [" + this.currLineRead + "]");
						this.fileReadNextLine();
					}
				} catch (Exception e) {
					this.errors.add("Error parsing Gedcom file [" + e.getMessage() + "] at line [" + this.currLineNbr + ":"
							+ this.currLineNbr + "]");
					this.fileReadNextLine();
				}
			}
		} catch (Exception e) {
			this.errors.add("Error parsing Gedcom file [" + e.getMessage() + "] at line [" + this.currLineNbr + ":"
					+ this.currLineRead + "]");
		}

		this.fileClose();

		// stop tracing
		//Debug.stopMethodTracing();
	}

	private void updateProgressHandler() {
		if (this.progressHandler != null) {
			this.progressHandler.removeMessages(this.currParsingProgress);
			this.currParsingProgress = this.currBytesRead;
			this.hndlrMsg = this.progressHandler.obtainMessage(this.currParsingProgress);
			this.progressHandler.sendMessage(this.hndlrMsg);
			//System.gc();
		}
	}
}
